﻿using System;
using System.Linq;

namespace MadLibrary.Text
{
    /// <summary>
    /// Holds characters options for text generation configuration.
    /// </summary>
    public enum SupportedCharacters
    {
        /// <summary>
        /// Characters a-z, 0-9
        /// </summary>
        AlphaNumeric,

        /// <summary>
        /// Characters 0-9
        /// </summary>
        Digits,

        /// <summary>
        /// Characters a-z
        /// </summary>
        EnglishLetters
    }

    /// <summary>
    ///  Holds case options for text generation configuration.
    /// </summary>
    public enum CharacterCase
    {
        /// <summary>
        /// Both cases
        /// </summary>
        Alternating,

        /// <summary>
        /// Uppercase letters only
        /// </summary>
        Uppercase,

        /// <summary>
        /// Lowercase letters only
        /// </summary>
        LowerCase
    }

    /// <summary>
    /// Serves as generator for random strings whichs' main functions can be called also as static.
    /// </summary>
    public class RandomText
    {
        /// <summary>
        /// Gets text generated.
        /// </summary>
        public string GeneratedText { get; private set; }

        /// <summary>
        /// Holds supported characters.
        /// </summary>
        public char[] SupportedCharacters { get; set; }

        /// <summary>
        /// Gets or sets minimal and also maximal length of string which has to be generated.
        /// </summary>
        public int Length { get; set; }

        /// <summary>
        /// Gets or sets option of character repeating.
        /// </summary>
        public bool RepeatCharacters { get; set; }

        /// <summary>
        /// Creates new RandomText object instance and sets properties into specified values.
        /// </summary>
        /// <param name="schars">Specifes an array of characters whicth can be used for string generation.</param>
        /// <param name="length">Specifies length for generation process.</param>
        /// <param name="repeat">Specifies option of character repeating.</param>
        public RandomText(char[] schars, int length, bool repeat = true)
        {
            this.GeneratedText = "";
            this.SupportedCharacters = schars;
            this.Length = length;
            this.RepeatCharacters = repeat;
        }

        /// <summary>
        /// Creates new RandomText object instance and sets properties into specified values.
        /// </summary>
        /// <param name="chars">Specifes three main mostly used groups of characters for random string generation.</param>
        /// <param name="c">Specifies case of characters which are in specified character gorup.</param>
        /// <param name="length">Specifies length for generation process.</param>
        /// <param name="repeat">Specifies option of character repeating.</param>
        public RandomText(SupportedCharacters chars, CharacterCase c, int length, bool repeat = true)
        {
            this.GeneratedText = "";
            this.SupportedCharacters = RandomText.GetSupportedCharacters(chars, c);
            this.Length = length;
            this.RepeatCharacters = repeat;
        }

        /// <summary>
        /// Generates stzring by options specified as properties and sets GeneratedText property to generated text.
        /// </summary>
        public void Generate()
        {
            Random r = new Random();
            for(int i = 0; i < this.Length; i++)
            {
                if(this.RepeatCharacters)
                    this.GeneratedText += this.SupportedCharacters[r.Next(this.SupportedCharacters.Length - 1)];
                else
                {
                    char gen = '\0';
                    while(this.GeneratedText.Contains((gen = this.SupportedCharacters[r.Next(this.SupportedCharacters.Length - 1)])))
                    {
                    }
                    this.GeneratedText += gen;
                }
            }
        }

        /// <summary>
        /// Staticaly generates text.
        /// </summary>
        /// <param name="schars">Specifes an array of characters whicth can be used for string generation.</param>
        /// <param name="length">pecifies length for generation process.</param>
        /// <param name="repeat">Specifies option of character repeating.</param>
        /// <returns></returns>
        public static string Generate(char[] schars, int length, bool repeat = true)
        {
            RandomText rt = new RandomText(schars, length, repeat);
            rt.Generate();
            return rt.GeneratedText;
        }

        /// <summary>
        /// Staticaly generates string.
        /// </summary>
        /// <param name="chars">Specifes three main mostly used groups of characters for random string generation.</param>
        /// <param name="c">Specifies case of characters which are in specified character gorup.</param>
        /// <param name="length">Specifies length for generation process.</param>
        /// <param name="repeat">Specifies option of character repeating.</param>
        /// <returns>Generated string.</returns>
        public static string Generate(SupportedCharacters chars, CharacterCase c, int length, bool repeat = true)
        {
            RandomText rt = new RandomText(RandomText.GetSupportedCharacters(chars, c), length, repeat);
            rt.Generate();
            return rt.GeneratedText;
        }

        /// <summary>
        /// Staticaly gets array of supported characters based on specified character group and character case parameters.
        /// </summary>
        /// <param name="chars">Specifies characters group.</param>
        /// <param name="c">Specifies characters case.</param>
        /// <returns>Array of supported characters.</returns>
        public static char[] GetSupportedCharacters(SupportedCharacters chars, CharacterCase c)
        {
            char[] ret = new char[0];
            switch(chars)
            {
                case MadLibrary.Text.SupportedCharacters.AlphaNumeric:
                    string pstring = "AbCdEfGhIjKlMnOpQrStUvXyZ0123456789";
                    if(c == CharacterCase.Alternating)
                        ret = pstring.ToCharArray();
                    else if(c == CharacterCase.LowerCase)
                        ret = pstring.ToLower().ToCharArray();
                    else
                        ret = pstring.ToUpper().ToCharArray();
                    break;

                case MadLibrary.Text.SupportedCharacters.EnglishLetters:
                    string pstr = "AbCdEfGhIjKlMnOpQrStUvXyZ";
                    if(c == CharacterCase.Alternating)
                        ret = pstr.ToCharArray();
                    else if(c == CharacterCase.LowerCase)
                        ret = pstr.ToLower().ToCharArray();
                    else
                        ret = pstr.ToUpper().ToCharArray();
                    break;

                case MadLibrary.Text.SupportedCharacters.Digits:
                    ret = "0123456789".ToCharArray();
                    break;
                default:
                    ret = RandomText.GetSupportedCharacters(MadLibrary.Text.SupportedCharacters.AlphaNumeric, CharacterCase.LowerCase);
                    break;
            }
            return ret;
        }
    }
}